package it.poli.IA.strategies;

import it.poli.IA.DecisionModule;

import it.poli.IA.exceptions.FailureException;
import it.poli.IA.exceptions.NullActionException;
import it.poli.IA.space.Action;
import it.poli.IA.space.Node;
import it.poli.IA.space.State;

import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
import java.util.List;

public class TreeSearchStrategy implements SearchStrategy {

	@Override
	public Collection<? extends Action> SomeSearch(Node s0, List<? extends Action> action, List<? extends State> Goals, Strategies strategy) throws FailureException
	{
		Node n;
		Deque<Node> frontier = new ArrayDeque<Node>();
		
		n = s0;
		frontier.addFirst(s0);
		Long infiniteLoopSaver = (long) 0;
		do
		{
			infiniteLoopSaver ++;
			if (frontier.isEmpty())
				throw new FailureException();
			
			n = frontier.removeFirst();
			if(Goals.contains(n.getCurrentState()))
			{
				return BuildSolution(n);
			}
			else
			{
				frontier.addAll(expNode(n, action));
			}
		}
		while(true);
		
		//return null;
	}


	public Deque<Node> expNode(Node n, List<? extends Action> actions) 
	{
		Node newNode;
		Deque<Node> successors = new ArrayDeque<Node>();
		
		for(Action a : actions)
		{
			try
			{
				if (DecisionModule.isAppliable(a, n.getCurrentState()))
				{
					newNode = new Node(DecisionModule.result(n.getCurrentState(), a),
							n, a,
							n.getTotalCost() + cost(n.getCurrentState() , a));
					successors.addLast(newNode);
					
					
				}
			} 
			catch (CloneNotSupportedException eee) {
				// TODO: handle exception
			}
			catch (NullActionException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
		
		return successors;
	}

	public
	 Integer cost(State currentState, Action a) {
		return 1; //each move costs one, the moving of the 
	}
	
	@Override
	public Deque<Action> BuildSolution(Node n) {
		
		Deque<Action> solution = new ArrayDeque<Action>();
		
		while(n.getParentNode() != null)
		{
			solution.addFirst(n.getPastAction());
			n = n.getParentNode();
			
		}
		System.out.println(" solution = " + solution);
		return solution;
	}


	
	
	
}
